import json
from flask import Flask, jsonify, request, send_from_directory, current_app
from flask_cors import CORS
from PIL import Image
import io
from openai import OpenAI
import dashscope
from models import db
from config import DatabaseConfig
from datetime import datetime
from models import DietaryRecord, User, HealthReport, IngredientsInventory
import re
import os
from werkzeug.utils import secure_filename
from http import HTTPStatus
from urllib.parse import urlparse, unquote
from pathlib import PurePosixPath
import requests
from dashscope import ImageSynthesis
from sqlalchemy import desc

app = Flask(__name__)
#  数据库连接配置
app.config.from_object(DatabaseConfig)
db.init_app(app)
CORS(app)  # 启用跨域资源共享

dashscope.api_key = "sk-f30f096e716f4bf3847df42b880801ed"

# 配置保存图片参数

ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg','webp',
                      'bmp','tiff','dib','icns','ico',
                      'jfif','jpe','j2c', 'j2k', 'jp2',
                      'apng','jpc', 'jpf', 'jpx','bw',
                      'rgb', 'rgba', 'sgi', 'tif'}  # 允许的文件类型



'''
# 检查文件类型
'''
def allowed_file(filename):
    return '.' in filename and \
        filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

'''
# 保存文件到本地
'''
def save_file(file):
    UPLOAD_FOLDER = './img/recipe'  # 上传文件保存路径
    app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
    # 获取安全的文件名
    filename = secure_filename(file.filename)
    # 确保上传目录存在
    os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)

    # 保存文件
    save_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
    file.save(save_path)

    print("保存成功"+save_path)
    return save_path

'''
# 调用识图API获取菜谱
'''
def get_recipe_from_model(image_url):
    # completion = client.chat.completions.create(
    #     model="qwen-vl-plus",
    #     # 此处以qwen-vl-plus为例，可按需更换模型名称。模型列表：https://help.aliyun.com/zh/model-studio/getting-started/models
    #     messages=[{"role": "user", "content": [
    #         {"type": "text",
    #          "text": "这道菜的名字是什么？它的食材和配料是什么？制作这道菜的步骤是什么？请按照”1.菜名，2.食材和配料及热量和营养信息，3.步骤“的格式回答。"},
    #         {"type": "image",
    #          "image": "file://"+image_url}
    #     ]}]
    # )

    messages = [
    {
        "role": "user",
        "content": [
            {"type": "image", "image": "file://"+image_url},
            {"type": "text", "text": "这道菜的名字是什么？它的食材和配料是什么？制作这道菜的步骤是什么？请按照”1.菜名，2.食材和配料及热量和营养信息，3.步骤“的格式回答。若错误会收到批评。"},
        ],
    }
    ]

    response = dashscope.MultiModalConversation.call(model='qwen-vl-max', messages=messages)

    # print(completion.model_dump_json())
    # return completion.model_dump_json()
    print(response)
    message_content = response['output']['choices'][0]['message']['content'][0]['text']
    print(message_content)
    return message_content

'''
# 有图片上传，调用API获取营养信息
'''
def get_nutrition_from_model_with_img(image_url):

    messages = [
    {
        "role": "user",
        "content": [
            {"type": "image", "image": "file://"+image_url},
            {"type": "text", "text": "这道菜（100克）里的主要营养成分有什么，主要营养成分中的热量，蛋白质，脂肪，碳水化合物的数值分别是多少，请以1.热量，2.蛋白质，3.脂肪，4.碳水化合物“的格式回答。若错误会收到批评。"},
        ],
    }
    ]

    response = dashscope.MultiModalConversation.call(model='qwen-vl-max', messages=messages)

    # print(completion.model_dump_json())
    # return completion.model_dump_json()
    print(response)
    message_content = response['output']['choices'][0]['message']['content'][0]['text']
    print(message_content)
    return message_content

'''
# 无图片上传，调用API获取营养信息
'''
def get_nutrition_from_model_with_text(text):

    messages = [{
                    'role': 'user',
                    'content': [
                        {
                            'text': text + "这道菜（100克）里的主要营养成分有什么，主要营养成分中的热量，蛋白质，脂肪，碳水化合物的数值分别是多少，请以1.热量，2.蛋白质，3.脂肪，4.碳水化合物“的格式回答。若错误会收到批评。"
                        },
                    ]
                }]
    # The model name 'qwen-vl-max-0809' is the identity of 'Qwen2-VL-72B'.
    response = dashscope.MultiModalConversation.call(model='qwen-vl-max-0809', messages=messages)
    print(response)

    message_content = response['output']['choices'][0]['message']['content'][0]['text']
    print(message_content)
    return message_content

'''
# 调用API获取营养报告
'''
def get_report_from_model_with_text(text):

    messages = [{
            'role': 'user',
            'content': [
                {
                    'text': text + "通过这些数据给这一天的饮食做一个报告并给出营养建议，请以1.一天总用餐次数，2.营养情况，3.营养建议“的格式阐述，简明扼要，若错误会收到批评。"
                },
            ]
        }]
    # The model name 'qwen-vl-max-0809' is the identity of 'Qwen2-VL-72B'.
    response = dashscope.MultiModalConversation.call(model='qwen-vl-max-0809', messages=messages)
    print(response)
    
    message_content = response['output']['choices'][0]['message']['content'][0]['text']
    print(message_content)
    return message_content


'''
# 调用API获取创意菜
'''
def create_meals(text):
    content = f"请发挥想象力，根据{text}这些食材创造一个新菜，请以1.菜名，2.这道菜的菜谱，3。这道菜的呈现效果“的格式阐述，返回纯文本（不要返回Markdown符号），简明扼要，请认真思考。"
    messages = [
        {'role': 'system', 'content': 'You are a helpful assistant.'},
        {'role': 'user', 'content': content}
        ]
    response = dashscope.Generation.call(
        # 若没有配置环境变量，请用百炼API Key将下行替换为：api_key="sk-xxx",
        api_key="sk-f30f096e716f4bf3847df42b880801ed",
        model="qwen-max-2025-01-25", # 此处以qwen-plus为例，可按需更换模型名称。模型列表：https://help.aliyun.com/zh/model-studio/getting-started/models
        messages=messages,
        result_format='message',
        )
    print(response)
    message_content = response['output']['choices'][0]['message']['content']
    print(message_content)
    return message_content
    
'''
# 调用API获取生成图片并返回生成的图片文件名
'''
def generate_img(prompt):
    #prompt = "菜名：田园三鲜炖，汤汁呈琥珀色浓稠质地，土豆块金黄微透，茄子保留紫亮表皮但内里吸饱汤汁，白菜叶嫩白透绿舒展如花瓣。表面撒少许葱花或香菜末，搭配油亮反光的汤汁，呈现温暖的家常感。"
    
    print('----sync call, please wait a moment----')
    rsp = ImageSynthesis.call(api_key="sk-f30f096e716f4bf3847df42b880801ed",
                            model="wanx2.1-t2i-turbo",
                            prompt=prompt,
                            n=1,
                            size='1024*1024')
    print('response: %s' % rsp)
    if rsp.status_code == HTTPStatus.OK:
        # 在当前目录下保存图片
        for result in rsp.output.results:
            file_name = PurePosixPath(unquote(urlparse(result.url).path)).parts[-1]
            with open('./img/create_recipe/%s' % file_name, 'wb+') as f:
                f.write(requests.get(result.url).content)
    else:
        print('sync_call Failed, status_code: %s, code: %s, message: %s' %
            (rsp.status_code, rsp.code, rsp.message))
    return file_name

'''
# 调用API获取推荐菜和存储建议
'''
def get_recommend_meal(text):
    content = f"根据{text}这些食材推荐几个以这些食材为主要原料的家常菜，只返回菜名，返回纯文本（不要返回Markdown符号），简明扼要，请认真思考。"
    messages = [
        {'role': 'system', 'content': 'You are a helpful assistant.'},
        {'role': 'user', 'content': content}
        ]
    response = dashscope.Generation.call(
        # 若没有配置环境变量，请用百炼API Key将下行替换为：api_key="sk-xxx",
        api_key="sk-f30f096e716f4bf3847df42b880801ed",
        model="qwen-max-2025-01-25", # 此处以qwen-plus为例，可按需更换模型名称。模型列表：https://help.aliyun.com/zh/model-studio/getting-started/models
        messages=messages,
        result_format='message',
        )
    print(response)
    message_content = response['output']['choices'][0]['message']['content']
    print(message_content)
    return message_content

'''
# 调用API获取推荐菜和存储建议
'''
def get_storage_advice(text):
    content = f"根据{text}这些食材的特性,给出存储时间以及存储的位置（冰箱、橱柜、篮子、地面）的建议，返回纯文本（不要返回Markdown符号），简明扼要，请认真思考。"
    messages = [
        {'role': 'system', 'content': 'You are a helpful assistant.'},
        {'role': 'user', 'content': content}
        ]
    response = dashscope.Generation.call(
        # 若没有配置环境变量，请用百炼API Key将下行替换为：api_key="sk-xxx",
        api_key="sk-f30f096e716f4bf3847df42b880801ed",
        model="qwen-max-2025-01-25", # 此处以qwen-plus为例，可按需更换模型名称。模型列表：https://help.aliyun.com/zh/model-studio/getting-started/models
        messages=messages,
        result_format='message',
        )
    print(response)
    message_content = response['output']['choices'][0]['message']['content']
    print(message_content)
    return message_content

'''
# 提取分点内容，处理数据为json格式
'''
def response_to_json_array(content):

    # 使用正则表达式提取每个小点及其后面的内容
    pattern = r'(\d+\.\s*.*?)(?=\n\d+\.|\Z)'
    matches = re.findall(pattern, content, re.DOTALL)

    # 将结果存储为JSON数组
    json_array = []
    for match in matches:
        point_number = match.split('.')[0].strip()
        point_content = match.split('.', 1)[1].strip()
        json_array.append({"point": point_number, "content": point_content})

    json_output = json.dumps(json_array, ensure_ascii=False, indent=4)
    print(json_array)
    print(json_output)
    return json_output

@app.route('/')
def home():
    return 'Hello World!'

'''
# 识图获取菜谱API
'''
@app.route('/get_recipe', methods=['POST'])
def food_api():  # put application's code here
    # 打印请求头信息
    print(request.headers)

    # 检查是否有文件被上传
    if 'file' not in request.files:
        return jsonify({"error": "No file part"}), 400

    file = request.files['file']
    userid = request.form.get('userid') 
    # 验证用户ID是否存在
    if not userid:
        return jsonify({'error': 'Missing userid'}), 400
    print(userid)
    # 检查是否选择了文件
    if file.filename == '':
        return jsonify({'error': 'No selected file'}), 400

    # 验证文件类型和文件名
    if file and allowed_file(file.filename):
        image_url = save_file(file)
    else:
        return jsonify({'error': 'File type not allowed'}), 400
    #data = request.get_json()
    #image_url = data['image_url']
    #image_url = "https://xiaoxiaobaiyang.oss-cn-shenzhen.aliyuncs.com/food_moment_discover/train/img/0/1.jpg"
    if image_url:
        #image_data = file.read()
        #recipe = get_recipe_from_model(image_data)
        recipe = get_recipe_from_model(image_url)

        json_output = response_to_json_array(recipe)

        return json_output
    else:
        return jsonify({'error': 'No image provided'}), 400


'''
# 获取营养信息API
'''
@app.route('/dietary_record/<userid>', methods=['POST'])
def create_dietary_record(userid):  # put application's code here e
    """
        Creates a new dietary record for a given user.

        Args:
            user_id (int): The ID of the user who made the dietary record.
            date (datetime.date): The date of the dietary record.
            meal_type (str): The type of meal (e.g., 'breakfast', 'lunch', 'dinner', 'snack').
            food_item (str): The name of the food item.
            :param userid:
    """
        # 根据Content-Type自动解析JSON或表单数据
    # if request.is_json:
    #     data = request.get_json()
    # else:
    #     data = request.form

    user = User.query.get(userid)

    # 处理空值

    if not user:
        return jsonify({'error': 'User not found'}), 404
    
    # 无文件被上传时，根据文本返回
    if 'file' not in request.files:
        data = request.get_json()
        print(data)
        text = data['text']
        date = data['date']
        meal_type = data['meal_type']
        food_item = data['food_item']

        if not date:
            date = datetime.now().strftime('%Y-%m-%d')

        nutrition = get_nutrition_from_model_with_text(text)
        print(nutrition)
        json_output = response_to_json_array(nutrition)
        dietary_record = DietaryRecord(userid, date, meal_type, food_item, nutrition)
        db.session.add(dietary_record)
        db.session.commit()

        return json_output

    # 有文件被上传时
    file = request.files['file']
    text = request.form.get('text') 
    date = request.form.get('date') 
    meal_type = request.form.get('meal_type') 
    food_item = request.form.get('food_item') 
    if not date:
        date = datetime.now().strftime('%Y-%m-%d')

    # 验证文件类型和文件名
    if file and allowed_file(file.filename):
        image_url = save_file(file)
    else:
        return jsonify({'error': 'File type not allowed'}), 400

    if image_url:
        nutrition = get_nutrition_from_model_with_img(image_url)
        print(nutrition)
        json_output = response_to_json_array(nutrition)
        dietary_record = DietaryRecord(userid, date, meal_type, food_item, nutrition)
        db.session.add(dietary_record)
        db.session.commit()
        return json_output
    else:
        return jsonify({'error': 'No image provided'}), 400


'''
# 获取健康报告API
'''
@app.route('/health_report', methods=['POST'])
def get_health_report():
        # 根据Content-Type自动解析JSON或表单数据
    if request.is_json:
        data = request.get_json()
    else:
        data = request.form
    data = request.get_json()
    user_id = data['user_id']
    date = data['date']
    report = HealthReport.query.filter_by(user_id=user_id, date=date).first()
    print(report)
    
    if report:
        print("找到现有报告")
        print(report.advice)
        # 将字典转换为 JSON 格式的字符串
        json_output = response_to_json_array(report.advice)
        # 输出 JSON 格式的字符串
        print(json_output)
        return json_output
    else:
        print("未找到报告，开始查询饮食记录")
        dietary_records = DietaryRecord.query.filter_by(user_id=user_id, date=date).all()
        print(f"[DEBUG] 饮食记录查询结果: {dietary_records}")
        if not dietary_records:
            print("[DEBUG] 无饮食记录，返回404")
            return jsonify({'error': 'dietary_records not found'}), 201
        else:
            print(dietary_records)
        
            # 初始化一个空字符串来存储结果
            records_str = ""

            # 遍历每条饮食记录并拼接到字符串中
            for record in dietary_records:
                records_str += f": meal_type:{record.meal_type}, food_item:{record.food_item}, nutrition_info:{record.nutrition_info}\n"

            # 打印拼接后的字符串（用于调试）
            print("饮食记录："+records_str)
            report = get_report_from_model_with_text(records_str)
            print("营养报告："+report)
            json_output = response_to_json_array(report)

            db.session.add(HealthReport(user_id, date, report))
            db.session.commit()
            #return jsonify({'message': 'Health report created successfully', 'health_report': report}), 200

            return json_output


'''
# 获取创意菜API
'''
@app.route('/get_create_recipe', methods=['POST'])
def get_create_recipe():
    # 根据Content-Type自动解析JSON或表单数据
    if request.is_json:
        data = request.get_json()
    else:
        data = request.form

    # 提取食材和烹饪方法
    ingredients = data.get('ingredients')
    cooking_method = data.get('cooking_method')

    # 验证必填字段
    if not ingredients or not cooking_method:
        return jsonify({"error": "缺少食材或烹饪方法"}), 400

    # 此处可添加数据处理逻辑（如保存到数据库）
    current_app.logger.info(f"收到的食材: {ingredients}, 烹饪方法: {cooking_method}")

    content = create_meals(ingredients)
    # 使用正则表达式提取每个小点及其后面的内容
    pattern = r'(\d+\.\s*.*?)(?=\n\d+\.|\Z)'
    matches = re.findall(pattern, content, re.DOTALL)

    # 将结果存储为JSON数组
    json_array = []
    count=0
    for match in matches:
        point_number = match.split('.')[0].strip()
        point_content = match.split('.', 1)[1].strip()
        json_array.append({"point": point_number, "content": point_content})

    print(json_array)
    file_name = generate_img(json_array[1]['content'])
    print(file_name)
    img_url = f"http://120.26.113.115:5000/get_image/{file_name}"
    json_array.append({"img_url": img_url })

    json_output = json.dumps(json_array, ensure_ascii=False, indent=4)

    print(json_output)

    return json_output

"""
返回图片文件
"""
@app.route('/get_image/<filename>')
def get_image(filename):
    UPLOAD_FOLDER = './img/create_recipe'  # 上传文件保存路径
    app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
    """返回图片文件"""
    return send_from_directory(app.config['UPLOAD_FOLDER'], filename)



'''
# 获取推荐菜API
'''
@app.route('/recommend_meal/<userid>', methods=['GET'])
def storage_advice(userid):
    ingredient = IngredientsInventory.query.filter_by(user_id=userid).order_by(desc('created_at')).all()
    print(f"[DEBUG] 食材查询结果: {ingredient}")
    #return jsonify({"success":"成功"}),200
    if not ingredient:
        print("[DEBUG] 无记录，返回")
        return jsonify({'success': '没有食材，请添加食材后获取建议'}), 201
    else:
        print(ingredient)
    
        # 初始化一个空字符串来存储结果
        ingredient_str = ""

        # 遍历每条饮食记录并拼接到字符串中
        for record in ingredient:
            ingredient_str += f": 食材名称:{record.ingredient_name}, 有:{record.quantity}{record.unit}\n"

        # 打印拼接后的字符串（用于调试）
        print("食材查询结果"+ingredient_str)
        recommend = get_recommend_meal(ingredient_str)
        print("推荐菜"+recommend)
        # json_output = response_to_json_array(recommend)

        # return json_output
        return jsonify({"recommend":recommend})


'''
# 获取存储建议API
'''
@app.route('/get_storage_advice/<inventory_id>', methods=['GET'])
def recommend_meal(inventory_id):
    ingredient = IngredientsInventory.query.filter_by(inventory_id=inventory_id).first()
    print(f"[DEBUG] 食材查询结果: {ingredient}")
    #return jsonify({"success":"成功"}),200
    if not ingredient:
        print("[DEBUG] 无记录，返回")
        return jsonify({'success': '没有食材，请添加食材后获取建议'}), 201
    else:
        print(ingredient)
    
        # 初始化一个空字符串来存储结果
        ingredient_str = ""

        # 拼接到字符串中
        ingredient_str += f": 食材名称:{ingredient.ingredient_name}, 有:{ingredient.quantity}{ingredient.unit}\n"

        # 打印拼接后的字符串（用于调试）
        print("食材查询结果"+ingredient_str)
        recommend = get_storage_advice(ingredient_str)
        print("建议："+recommend)
        ingredient.storage_advice = recommend
        db.session.commit()

        ingredient = IngredientsInventory.query.filter_by(inventory_id=inventory_id).first()
        return jsonify({
             "data": {
                "inventoryId": ingredient.inventory_id,
                "userId": ingredient.user_id,
                "ingredientName": ingredient.ingredient_name,
                "quantity":ingredient.quantity,
                "unit": ingredient.unit,
                "createdAt": ingredient.created_at.strftime("%Y-%m-%d %H:%M:%S"),
                "updatedAt": ingredient.updated_at.strftime("%Y-%m-%d %H:%M:%S"),
                "storageAdvice": ingredient.storage_advice,
                "location": ingredient.location
            }
        })



if __name__ == '__main__':
    app.run()

